#include "ApplicationFactory.h"
#include "SequenceFunctionFactory.h"

#include "sequencerunner.h"
#include "SequenceModel.h"

#include "LightPresetModel.h"
#include "MediaListModel.h"

#include "FileInport.h"
#include "ApplicationSettings.h"
#include "ShowManager.h"
#include "ShowFactory.h"

#include "ScriptFunctionFactory.h"
#include "ScriptEngine.h"

#include "PlaylistFunctionFactory.h"
#include "PlaylistGuiFactory.h"
#include "PlaylistBar.h"
#include "ActionListController.h"
#include "ActionListView.h"
#include "volumeslider.h"
#include "ExponentialFader.h"
#include "MediaListModel.h"
#include "AudioVideoAutomation.h"
#include "PictureAutomation.h"

#include "LightFunctionFactory.h"
#include "LightPresetFactory.h"
#include "lightControlGuiFactory.h"
#include "IF_LightEngineInterface.h"
#include "IF_DmxSliderPanel.h"
#include "IF_GuiLightControlPanel.h"

#include "mainwindow.h"
#include "QAction"


#define NUMBER_OF_DMX_CHANNELS    12


ApplicationFactory::ApplicationFactory()
{
   ApplicationSettings *applicationSettings = new ApplicationSettings( this);
   FileInport *fileInport = new FileInport( *applicationSettings, this);

   /* main window */
   m_mainWindow = new MainWindow( *fileInport, *applicationSettings, NULL);

   /* light control function */
   LightFunctionFactory *lightFactory = new LightFunctionFactory( this);
   LightPresetFactory *lightPresetFactory = new LightPresetFactory( this);

   IF_LightTransitionEngine *transitionEngine = lightFactory->buildTransitionEngine( NUMBER_OF_DMX_CHANNELS);
   LightPresetModel *lightModel = lightFactory->buildModel( NUMBER_OF_DMX_CHANNELS,
                                                            *lightPresetFactory);
   ActionListController *lightViewController = new ActionListController( *lightModel, this);
   IF_LightEngineInterface *lightEngine = lightFactory->buildLightEngine( *lightModel, *transitionEngine,
                                                                          *lightViewController);

   LightControlGuiFactory *lightGuiFactory = new LightControlGuiFactory( NUMBER_OF_DMX_CHANNELS,
                                                                         m_mainWindow);


   IF_DmxSliderPanel *sliderPanel = lightGuiFactory->buildDmxSliderPanel( lightEngine, transitionEngine,
                                                                          m_mainWindow);
   IF_GuiLightControlPanel *lightPresetPanel;
   lightPresetPanel = lightGuiFactory->buildPresetListViewer( lightEngine, lightModel,
                                                              lightViewController, m_mainWindow);

   connect( m_mainWindow, SIGNAL(mainWindowAboutToClose()), lightEngine, SLOT(requestDmxStop()) );

   lightGuiFactory->buildLightControlPanel( lightModel, lightEngine, sliderPanel, lightPresetPanel,
                                            m_mainWindow->lightControlArea());
   m_mainWindow->setLightControlActions( lightGuiFactory->buildActions( lightPresetPanel));


   /* playlist function */
   PlaylistFunctionFactory *playlistFactory;
   playlistFactory = new PlaylistFunctionFactory( this);

   MediaListModel *playlistModel = playlistFactory->buildModel();
   IF_MediaEngineInterface *mediaEngine = playlistFactory->buildAudioVideoEngine();
   IF_PictureEngineInterface *pictureEngine = playlistFactory->buildPictureEngine();

   PlaylistGuiFactory *playGuiFactory = new PlaylistGuiFactory( this);
   AudioVideoPlayBar *audvidPlaybar = playGuiFactory->buildAudioVideoPlaybar( mediaEngine, m_mainWindow);
   PicturePlaybar * pictPlaybar = playGuiFactory->buildPicturePlaybar( pictureEngine, m_mainWindow);
   PlaylistBar * playlistBar = playGuiFactory->buildPlaylistBar( audvidPlaybar, pictPlaybar,
                                                                 playlistModel, m_mainWindow);
   ActionListController *mediaActionController = new ActionListController( *playlistModel, this);
   ActionListView *playlistView = playGuiFactory->buildPlaylistView( playlistBar, playlistModel,
                                                                     mediaActionController,
                                                                     m_mainWindow);

   ExponentialFader *expFader = new ExponentialFader( this);
   AudioVideoAutomation *audioVideoAutomation = playlistFactory->buildAutomation( playlistModel, mediaEngine,
                                                                              mediaActionController,
                                                                              expFader, *applicationSettings);
   playGuiFactory->buildPlaylistPanel( mediaEngine, audioVideoAutomation, playlistView, fileInport,
                                       m_mainWindow->playlistArea());

   PictureAutomation *pictureAutomation = playlistFactory->buildPictureAutomation( playlistModel,
                                                                                   pictureEngine,
                                                                                   mediaActionController);

   playGuiFactory->buildVolumeBar( mediaEngine, m_mainWindow->volumeSliderArea() );

   connect( m_mainWindow, SIGNAL(mainWindowAboutToClose()), audioVideoAutomation, SLOT(onClosing()) );

   connect( mediaActionController, SIGNAL(activeRowChanged(int)),
            audioVideoAutomation, SLOT(activateByRowNumer(int)) );

   connect( mediaActionController, SIGNAL(activeRowChanged(int)),
            pictureAutomation, SLOT(activateByRowNumer(int)) );

   connect( mediaActionController, SIGNAL(activeRowChanged(int)),
            playlistBar, SLOT(onActiveRowChanged(int)) );

   QList<QAction *> playlistActions = playlistFactory->buildActionList( mediaEngine,
                                                                        audioVideoAutomation);
   m_mainWindow->setMediaListActions( playlistActions);

   /* 'show changed' notification */
   connect( lightModel, SIGNAL(layoutChanged()), m_mainWindow, SLOT(onShowChanged()) );
   connect( playlistModel, SIGNAL(layoutChanged()), m_mainWindow, SLOT(onShowChanged()) );

   /* sequence function */
   SequenceRunner * sequenceRunner;
   SequenceModel * sequenceModel;
   m_sequenceFactory = new SequenceFunctionFactory( this);
   sequenceModel = m_sequenceFactory->buildModel();
   sequenceRunner = m_sequenceFactory->buildEngine( m_mainWindow->sequenceFunctionArea(),
                                                    sequenceModel, playlistModel, lightModel);

   wireSequenceFunction( sequenceRunner, sequenceModel, audioVideoAutomation,
                         pictureAutomation, lightEngine);
   createSequenceActions(sequenceRunner);

   /* script function */
   m_scriptFactory = new ScriptFunctionFactory( this);
   ScriptEngine *scriptEngine = m_scriptFactory->build( m_mainWindow->scriptArea(),
                                                        playlistModel, lightModel);

   wireScriptFunction( scriptEngine, audioVideoAutomation, pictureAutomation, lightEngine);
   m_mainWindow->setScriptActions( scriptEngine->getActionList() );

   /* show function */
   ShowFactory *showFactory = new ShowFactory( NUMBER_OF_DMX_CHANNELS, *applicationSettings, this);
   ShowManager *show = new ShowManager( showFactory, *scriptEngine, *playlistModel,
                                        *lightModel, *sequenceModel, *applicationSettings, this);

   wireShowFunction( show, scriptEngine);

   /* file inport function */
   connect( fileInport, SIGNAL(inportShowFile(QString)),
            show, SLOT(loadShowFile(QString)) );
   connect( fileInport, SIGNAL(inportScriptContent(QString)),
            scriptEngine, SLOT(setScriptContent(QString)) );
   connect( fileInport, SIGNAL(inportMediaTracks(QStringList)),
            playlistModel, SLOT(addMediaFiles(QStringList)) );
}

ApplicationFactory::~ApplicationFactory()
{
   delete m_mainWindow;
   delete m_sequenceFactory;
}

/**
 * create actions related with "Sequence" functionality and link
 * main window menu to engine functions.
 * @param sequenceRunner - engine of sequence function
 */
void ApplicationFactory::createSequenceActions(SequenceRunner *sequenceRunner)
{
   QAction * sequencePlay = new QAction( tr("&play"), this);
   sequencePlay->setShortcut( Qt::Key_F5);
   connect( sequencePlay, SIGNAL(triggered()), sequenceRunner, SLOT(play()) );
   connect( sequenceRunner, SIGNAL(sequenceIsRunning(bool)), sequencePlay, SLOT(setDisabled(bool)) );

   QAction * sequencePause = new QAction( tr("p&ause"), this);
   sequencePause->setShortcut( Qt::Key_F6);
   sequencePause->setEnabled( false);
   connect( sequencePause, SIGNAL(triggered()), sequenceRunner, SLOT(pause()) );
   connect( sequenceRunner, SIGNAL(sequenceIsRunning(bool)), sequencePause, SLOT(setEnabled(bool)) );

   m_mainWindow->setSequenceActions( QList<QAction *>() << sequencePlay << sequencePause);
}

/**
 * wire "Sequence" function to other functions
 */
void ApplicationFactory::wireSequenceFunction( SequenceRunner *sequenceRunner,
                                               SequenceModel * sequenceModel,
                                               AudioVideoAutomation *avAutomation,
                                               PictureAutomation *picAutomation,
                                               IF_LightEngineInterface *lightEngine)
{
   connect( sequenceRunner, SIGNAL(activateLight(QString,bool)),
            lightEngine, SLOT(activateByName(QString,bool)) );

   connect( sequenceRunner, SIGNAL(activateMedia(QString,bool)),
            avAutomation, SLOT(activateById(QString,bool)) );

   connect( sequenceRunner, SIGNAL(activatePicture(QString,bool)),
            picAutomation, SLOT(activateById(QString,bool)) );

   connect( sequenceModel, SIGNAL(layoutChanged()), m_mainWindow, SLOT(onShowChanged()) );
}

void ApplicationFactory::wireScriptFunction( ScriptEngine *scriptEngine,
                                             AudioVideoAutomation *avAutomation,
                                             PictureAutomation *picAutomation,
                                             IF_LightEngineInterface *lightEngine)
{
   connect( scriptEngine, SIGNAL(activateLight(QString,bool)),
            lightEngine, SLOT(activateByName(QString,bool)) );

   connect( scriptEngine, SIGNAL(activateMedia(QString,bool)),
            avAutomation, SLOT(activateById(QString,bool)) );

   connect( scriptEngine, SIGNAL(activatePicture(QString,bool)),
            picAutomation, SLOT(activateById(QString,bool)) );

   connect( scriptEngine, SIGNAL(textChanged()), m_mainWindow, SLOT(onShowChanged()) );
}

void ApplicationFactory::wireShowFunction(ShowManager *show, ScriptEngine *scriptEngine)
{
   connect( m_mainWindow, SIGNAL(loadShowFile(QString)), show, SLOT(loadShowFile(QString)) );
   connect( m_mainWindow, SIGNAL(saveShowTriggered()), show, SLOT(onSaveShowRequest()) );
   connect( m_mainWindow, SIGNAL(saveShowAsTriggered()), show, SLOT(onSaveShowAsRequest()) );
   connect( m_mainWindow, SIGNAL(openShowTriggered()), show, SLOT(openFile()) );

   connect( show, SIGNAL(scriptContent(QString)), scriptEngine, SLOT(setScriptContent(QString)) );
   connect( show, SIGNAL(showNameChanged(QString)), m_mainWindow, SLOT(onShowNameChanged(QString)) );
   connect( show, SIGNAL(showSaved(QString)), m_mainWindow, SLOT(onShowSaved(QString)) );
   connect( show, SIGNAL(newSearchPath(QString)), scriptEngine, SIGNAL(newSearchPath(QString)) );
}

